package com.papercutting.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.papercutting.platform.dto.query.TutorialQuery;
import com.papercutting.platform.dto.request.TutorialRequest;
import com.papercutting.platform.dto.response.PageResult;
import com.papercutting.platform.dto.response.TutorialResponse;
import com.papercutting.platform.dto.response.TutorialStepResponse;
import com.papercutting.platform.entity.Tutorial;
import com.papercutting.platform.entity.TutorialStep;
import com.papercutting.platform.entity.UserLike;
import com.papercutting.platform.entity.UserFavorite;
import com.papercutting.platform.exception.BusinessException;
import com.papercutting.platform.repository.TutorialRepository;
import com.papercutting.platform.repository.TutorialStepRepository;
import com.papercutting.platform.repository.UserLikeRepository;
import com.papercutting.platform.repository.UserFavoriteRepository;
import com.papercutting.platform.service.TutorialService;
import com.papercutting.platform.util.ImageUrlUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 教程服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TutorialServiceImpl implements TutorialService {

    private final TutorialRepository tutorialRepository;
    private final TutorialStepRepository tutorialStepRepository;
    private final UserLikeRepository userLikeRepository;
    private final UserFavoriteRepository userFavoriteRepository;
    private final ImageUrlUtil imageUrlUtil;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTutorial(TutorialRequest request) {
        log.info("创建教程: {}", request.getTitle());

        // 创建教程实体
        Tutorial tutorial = new Tutorial();
        BeanUtils.copyProperties(request, tutorial);
        tutorial.setStepsCount(0); // 初始步骤数为0
        tutorial.setViewCount(0);
        tutorial.setLikeCount(0);
        tutorial.setFavoriteCount(0);
        tutorial.setStudyCount(0);

        // 保存教程
        tutorialRepository.insert(tutorial);

        log.info("教程创建成功，ID: {}", tutorial.getId());
        return tutorial.getId();
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTutorial(TutorialRequest request) {
        log.info("更新教程: {}", request.getId());

        // 查找现有教程
        Tutorial tutorial = tutorialRepository.selectById(request.getId());
        if (tutorial == null) {
            throw new RuntimeException("教程不存在");
        }

        // 更新教程信息
        BeanUtils.copyProperties(request, tutorial, "id", "createTime", "viewCount", "likeCount", "favoriteCount", "studyCount");

        // 保存更新
        tutorialRepository.updateById(tutorial);

        log.info("教程更新成功: {}", request.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTutorial(Long id) {
        log.info("删除教程: {}", id);

        // 检查教程是否存在
        Tutorial tutorial = tutorialRepository.selectById(id);
        if (tutorial == null) {
            // 返回业务异常，避免抛出运行时异常导致 500
            throw new BusinessException(404, "教程不存在");
        }

        // 使用MyBatis Plus的逻辑删除
        tutorialRepository.deleteById(id);

        // 软删除相关步骤
        LambdaQueryWrapper<TutorialStep> stepWrapper = new LambdaQueryWrapper<>();
        stepWrapper.eq(TutorialStep::getTutorialId, id);
        List<TutorialStep> steps = tutorialStepRepository.selectList(stepWrapper);
        if (!steps.isEmpty()) {
            List<Long> stepIds = steps.stream().map(TutorialStep::getId).collect(Collectors.toList());
            tutorialStepRepository.deleteBatchIds(stepIds);
        }

        log.info("教程删除成功: {}", id);
    }
    
    @Override
    public Map<String, Object> getTutorialById(Long id) {
        log.info("获取教程详情: {}", id);

        // 查找教程
        Tutorial tutorial = tutorialRepository.selectById(id);
        if (tutorial == null) {
            throw new RuntimeException("教程不存在");
        }

        // 转换为响应对象
        TutorialResponse response = convertToResponse(tutorial);

        // 查找教程步骤
        LambdaQueryWrapper<TutorialStep> stepWrapper = new LambdaQueryWrapper<>();
        stepWrapper.eq(TutorialStep::getTutorialId, id)
                   .eq(TutorialStep::getDeleted, false)
                   .orderByAsc(TutorialStep::getStepNumber);
        List<TutorialStep> steps = tutorialStepRepository.selectList(stepWrapper);
        List<TutorialStepResponse> stepResponses = steps.stream()
                .map(this::convertStepToResponse)
                .collect(Collectors.toList());

        // 构建结果
        Map<String, Object> result = new HashMap<>();
        result.put("tutorial", response);
        result.put("steps", stepResponses);

        return result;
    }
    
    @Override
    public PageResult<TutorialResponse> getTutorialPage(TutorialQuery query) {
        log.info("分页查询教程列表: {}", query);

        try {
            // 构建查询条件
            LambdaQueryWrapper<Tutorial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Tutorial::getDeleted, false);

            // 标题模糊查询
            if (StringUtils.hasText(query.getTitle())) {
                wrapper.like(Tutorial::getTitle, query.getTitle());
            }

            // 分类查询
            if (query.getCategory() != null) {
                wrapper.eq(Tutorial::getCategory, query.getCategory());
            }

            // 难度级别查询
            if (query.getDifficultyLevel() != null) {
                wrapper.eq(Tutorial::getDifficultyLevel, query.getDifficultyLevel());
            }

            // 状态查询 - 如果指定了status参数，则按状态过滤；否则查询所有状态（管理后台需要）
            if (query.getStatus() != null) {
                wrapper.eq(Tutorial::getStatus, query.getStatus());
            }
            // 移除默认status=1的限制，让管理后台能看到所有状态的教程

            // 推荐状态查询
            if (query.getIsRecommend() != null) {
                wrapper.eq(Tutorial::getIsRecommend, query.getIsRecommend());
            }

            // 免费状态查询
            if (query.getIsFree() != null) {
                wrapper.eq(Tutorial::getIsFree, query.getIsFree());
            }

            // 创建者查询
            if (query.getCreatorId() != null) {
                wrapper.eq(Tutorial::getCreatorId, query.getCreatorId());
            }

            // 标签模糊查询
            if (StringUtils.hasText(query.getTags())) {
                wrapper.like(Tutorial::getTags, query.getTags());
            }

            // 排序：推荐优先，然后按排序号，最后按创建时间倒序
            wrapper.orderByDesc(Tutorial::getIsRecommend)
                   .orderByAsc(Tutorial::getSortOrder)
                   .orderByDesc(Tutorial::getCreateTime);

            // 分页查询
            Page<Tutorial> page = new Page<>(query.getPage(), query.getSize());
            IPage<Tutorial> result = tutorialRepository.selectPage(page, wrapper);

            // 转换为响应对象
            List<TutorialResponse> responses = result.getRecords().stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());

            return PageResult.of(responses, result.getTotal(), query.getPage(), query.getSize());

        } catch (Exception e) {
            log.error("分页查询教程列表失败", e);
            return PageResult.of(new ArrayList<>(), 0L, query.getPage(), query.getSize());
        }
    }
    
    @Override
    public List<TutorialResponse> getTutorialList(TutorialQuery query) {
        log.info("获取教程列表: {}", query);

        try {
            // 构建查询条件
            LambdaQueryWrapper<Tutorial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Tutorial::getDeleted, false);

            // 应用查询条件（与分页查询相同的逻辑）
            if (StringUtils.hasText(query.getTitle())) {
                wrapper.like(Tutorial::getTitle, query.getTitle());
            }
            if (query.getCategory() != null) {
                wrapper.eq(Tutorial::getCategory, query.getCategory());
            }
            if (query.getDifficultyLevel() != null) {
                wrapper.eq(Tutorial::getDifficultyLevel, query.getDifficultyLevel());
            }
            if (query.getStatus() != null) {
                wrapper.eq(Tutorial::getStatus, query.getStatus());
            }
            if (query.getIsRecommend() != null) {
                wrapper.eq(Tutorial::getIsRecommend, query.getIsRecommend());
            }
            if (query.getIsFree() != null) {
                wrapper.eq(Tutorial::getIsFree, query.getIsFree());
            }

            // 排序
            wrapper.orderByDesc(Tutorial::getIsRecommend)
                   .orderByAsc(Tutorial::getSortOrder)
                   .orderByDesc(Tutorial::getCreateTime);

            List<Tutorial> tutorials = tutorialRepository.selectList(wrapper);

            return tutorials.stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("获取教程列表失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<TutorialResponse> getRecommendedTutorials(Integer limit) {
        log.info("获取推荐教程列表: limit={}", limit);

        try {
            LambdaQueryWrapper<Tutorial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Tutorial::getDeleted, false)
                   .eq(Tutorial::getIsRecommend, 1)
                   .eq(Tutorial::getStatus, 1) // 只查询已发布的
                   .orderByAsc(Tutorial::getSortOrder)
                   .orderByDesc(Tutorial::getCreateTime);

            if (limit != null && limit > 0) {
                wrapper.last("LIMIT " + limit);
            }

            List<Tutorial> tutorials = tutorialRepository.selectList(wrapper);

            return tutorials.stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("获取推荐教程列表失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<TutorialResponse> getFreeTutorials(Integer limit) {
        log.info("获取免费教程列表: limit={}", limit);

        try {
            LambdaQueryWrapper<Tutorial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Tutorial::getDeleted, false)
                   .eq(Tutorial::getIsFree, 1)
                   .eq(Tutorial::getStatus, 1) // 只查询已发布的
                   .orderByAsc(Tutorial::getSortOrder)
                   .orderByDesc(Tutorial::getCreateTime);

            if (limit != null && limit > 0) {
                wrapper.last("LIMIT " + limit);
            }

            List<Tutorial> tutorials = tutorialRepository.selectList(wrapper);

            return tutorials.stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("获取免费教程列表失败", e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public void increaseViewCount(Long id) {
        log.info("增加浏览量: {}", id);

        try {
            Tutorial tutorial = tutorialRepository.selectById(id);
            if (tutorial == null) {
                throw new RuntimeException("教程不存在");
            }

            tutorial.setViewCount((tutorial.getViewCount() == null ? 0 : tutorial.getViewCount()) + 1);
            tutorialRepository.updateById(tutorial);

        } catch (Exception e) {
            log.error("增加浏览量失败: {}", id, e);
        }
    }

    @Override
    public PageResult<TutorialResponse> searchTutorial(String keyword, TutorialQuery query) {
        log.info("搜索教程内容: {}", keyword);

        try {
            // 构建搜索条件
            LambdaQueryWrapper<Tutorial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Tutorial::getDeleted, false);

            // 关键词搜索：标题、内容、标签
            if (StringUtils.hasText(keyword)) {
                wrapper.and(w -> w.like(Tutorial::getTitle, keyword)
                                 .or().like(Tutorial::getContent, keyword)
                                 .or().like(Tutorial::getTags, keyword)
                                 .or().like(Tutorial::getSummary, keyword));
            }

            // 应用其他查询条件
            if (query.getCategory() != null) {
                wrapper.eq(Tutorial::getCategory, query.getCategory());
            }
            if (query.getDifficultyLevel() != null) {
                wrapper.eq(Tutorial::getDifficultyLevel, query.getDifficultyLevel());
            }
            // 默认只查询已发布的内容（status=1），除非明确指定了status参数
            if (query.getStatus() != null) {
                wrapper.eq(Tutorial::getStatus, query.getStatus());
            } else {
                wrapper.eq(Tutorial::getStatus, 1);
            }

            // 排序
            wrapper.orderByDesc(Tutorial::getIsRecommend)
                   .orderByAsc(Tutorial::getSortOrder)
                   .orderByDesc(Tutorial::getCreateTime);

            // 分页查询
            Page<Tutorial> page = new Page<>(query.getPage(), query.getSize());
            IPage<Tutorial> result = tutorialRepository.selectPage(page, wrapper);

            // 转换为响应对象
            List<TutorialResponse> responses = result.getRecords().stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());

            return PageResult.of(responses, result.getTotal(), query.getPage(), query.getSize());

        } catch (Exception e) {
            log.error("搜索教程失败", e);
            return PageResult.of(new ArrayList<>(), 0L, query.getPage(), query.getSize());
        }
    }

    @Override
    public List<Map<String, Object>> getCategoryStats() {
        log.info("获取分类统计");

        try {
            List<Map<String, Object>> stats = new ArrayList<>();

            // 统计各分类的教程数量
            for (int category = 1; category <= 3; category++) {
                LambdaQueryWrapper<Tutorial> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(Tutorial::getDeleted, false)
                       .eq(Tutorial::getCategory, category);

                long count = tutorialRepository.selectCount(wrapper);

                Map<String, Object> stat = new HashMap<>();
                stat.put("category", category);
                stat.put("categoryText", getCategoryText(category));
                stat.put("count", count);

                stats.add(stat);
            }

            return stats;

        } catch (Exception e) {
            log.error("获取分类统计失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateStatus(List<Long> ids, Integer status) {
        log.info("批量更新状态: {} -> {}", ids, status);

        try {
            List<Tutorial> tutorials = tutorialRepository.selectBatchIds(ids);

            tutorials.forEach(tutorial -> {
                if (!tutorial.getDeleted()) {
                    tutorial.setStatus(status);
                    tutorialRepository.updateById(tutorial);
                }
            });

            log.info("批量更新状态成功: 更新了{}条记录", tutorials.size());

        } catch (Exception e) {
            log.error("批量更新状态失败", e);
            throw new RuntimeException("批量更新状态失败");
        }
    }
    
    @Override
    public List<Tutorial> findAll() {
        return tutorialRepository.selectList(null);
    }

    /**
     * 转换教程实体为响应对象
     */
    private TutorialResponse convertToResponse(Tutorial tutorial) {
        TutorialResponse response = new TutorialResponse();
        BeanUtils.copyProperties(tutorial, response);

        // 处理图片和视频URL，拼接完整路径
        if (tutorial.getCoverImage() != null) {
            response.setCoverImage(imageUrlUtil.processImageUrl(tutorial.getCoverImage()));
        }
        if (tutorial.getVideoUrl() != null) {
            response.setVideoUrl(imageUrlUtil.processImageUrl(tutorial.getVideoUrl()));
        }

        // 设置文本字段
        response.setDifficultyLevelText(getDifficultyLevelText(tutorial.getDifficultyLevel()));
        response.setCategoryText(getCategoryText(tutorial.getCategory()));
        response.setStatusText(getStatusText(tutorial.getStatus()));

        return response;
    }

    /**
     * 转换教程步骤实体为响应对象
     */
    private TutorialStepResponse convertStepToResponse(TutorialStep step) {
        TutorialStepResponse response = new TutorialStepResponse();
        BeanUtils.copyProperties(step, response);
        
        // 处理图片和视频URL，拼接完整路径
        if (step.getImageUrl() != null) {
            response.setImageUrl(imageUrlUtil.processImageUrl(step.getImageUrl()));
        }
        if (step.getVideoUrl() != null) {
            response.setVideoUrl(imageUrlUtil.processImageUrl(step.getVideoUrl()));
        }
        
        return response;
    }

    /**
     * 获取难度级别文本
     */
    private String getDifficultyLevelText(Integer level) {
        if (level == null) return "";
        switch (level) {
            case 1: return "初级";
            case 2: return "中级";
            case 3: return "高级";
            default: return "未知";
        }
    }

    /**
     * 获取分类文本
     */
    private String getCategoryText(Integer category) {
        if (category == null) return "";
        switch (category) {
            case 1: return "基础入门";
            case 2: return "进阶技法";
            case 3: return "高级创作";
            default: return "未知";
        }
    }

    /**
     * 获取状态文本
     */
    private String getStatusText(Integer status) {
        if (status == null) return "";
        switch (status) {
            case 0: return "草稿";
            case 1: return "已发布";
            case 2: return "已下架";
            default: return "未知";
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> likeTutorial(Long tutorialId, Long userId) {
        log.info("=== 开始点赞操作 ===");
        log.info("用户{}点赞教程: {}", userId, tutorialId);

        // 参数校验
        if (tutorialId == null || tutorialId <= 0) {
            log.warn("点赞失败: 教程ID无效 - {}", tutorialId);
            throw new BusinessException("教程ID无效");
        }
        
        if (userId == null || userId <= 0) {
            log.warn("点赞失败: 用户ID无效 - {}", userId);
            throw new BusinessException("用户未登录或登录已过期，请重新登录");
        }

        // 使用用户+教程维度的同步锁，防止同一用户对同一教程的并发操作
        String lockKey = "like_tutorial_" + userId + "_" + tutorialId;
        synchronized (lockKey.intern()) {
            try {
                // 检查教程是否存在
                Tutorial tutorial = tutorialRepository.selectById(tutorialId);
                if (tutorial == null) {
                    log.warn("点赞失败: 教程不存在 - tutorialId={}", tutorialId);
                    throw new BusinessException("教程不存在");
                }
                
                // 检查教程状态
                if (tutorial.getDeleted() || tutorial.getStatus() != 1) {
                    log.warn("点赞失败: 教程状态无效 - tutorialId={}, deleted={}, status={}", 
                            tutorialId, tutorial.getDeleted(), tutorial.getStatus());
                    throw new BusinessException("该教程暂时无法点赞");
                }

                // 使用幂等操作处理点赞
                Map<String, Object> result = handleLikeIdempotent(userId, tutorialId, tutorial);
                
                log.info("=== 点赞操作完成 ===");
                return result;

            } catch (BusinessException e) {
                // 业务异常直接抛出
                log.warn("点赞教程业务异常: tutorialId={}, userId={}, message={}", tutorialId, userId, e.getMessage());
                throw e;
            } catch (org.springframework.dao.DuplicateKeyException e) {
                // 专门处理重复键异常
                log.warn("检测到重复键异常，转为幂等处理: tutorialId={}, userId={}", tutorialId, userId);
                return handleDuplicateKeyException(userId, tutorialId);
            } catch (Exception e) {
                log.error("点赞教程系统异常: tutorialId={}, userId={}, error={}", tutorialId, userId, e.getMessage(), e);
                throw new BusinessException("点赞操作失败，请稍后重试");
            }
        }
    }
    
    /**
     * 幂等处理点赞操作
     */
    private Map<String, Object> handleLikeIdempotent(Long userId, Long tutorialId, Tutorial tutorial) {
        log.info("执行幂等点赞处理: userId={}, tutorialId={}", userId, tutorialId);
        
        // 查询现有记录（包括已删除的）- 使用自定义SQL绕过@TableLogic
        List<UserLike> allLikes = userLikeRepository.findAllRecords(userId, "tutorial", tutorialId);
        log.info("查询到{}条相关记录（包括已删除）", allLikes.size());
        
        // 打印详细的记录信息用于调试
        for (UserLike like : allLikes) {
            log.info("记录详情: ID={}, deleted={}, createTime={}", 
                    like.getId(), like.getDeleted(), like.getCreateTime());
        }
        
        // 查找有效记录
        UserLike activeLike = allLikes.stream()
                .filter(like -> !like.getDeleted())
                .findFirst()
                .orElse(null);

        boolean newLikedStatus;
        
        if (activeLike != null) {
            // 已点赞，执行取消点赞 - 使用专门的软删除方法绕过逻辑删除限制
            log.info("发现有效点赞记录，执行取消点赞: 记录ID={}", activeLike.getId());
            int updateResult = userLikeRepository.softDeleteRecord(activeLike.getId());
            log.info("取消点赞更新结果: {}", updateResult);
            
            // 更新点赞数
            Integer currentLikeCount = tutorial.getLikeCount() == null ? 0 : tutorial.getLikeCount();
            tutorial.setLikeCount(Math.max(0, currentLikeCount - 1));
            newLikedStatus = false;
            log.info("取消点赞成功: 记录ID={}, 新的点赞数={}", activeLike.getId(), tutorial.getLikeCount());
        } else {
            // 未点赞，执行点赞操作
            log.info("未发现有效点赞记录，执行点赞操作");
            UserLike deletedLike = allLikes.stream()
                    .filter(UserLike::getDeleted)
                    .findFirst()
                    .orElse(null);
            
            if (deletedLike != null) {
                // 重用已删除记录 - 使用专门的恢复方法绕过逻辑删除限制
                log.info("重用已删除记录: 记录ID={}", deletedLike.getId());
                int updateResult = userLikeRepository.restoreRecord(deletedLike.getId());
                log.info("重用记录更新结果: {}", updateResult);
                
                if (updateResult == 0) {
                    log.warn("重用记录失败，创建新记录替代: 原记录ID={}", deletedLike.getId());
                    // 如果重用失败，创建新记录
                    UserLike newLike = new UserLike();
                    newLike.setUserId(userId);
                    newLike.setTargetType("tutorial");
                    newLike.setTargetId(tutorialId);
                    newLike.setDeleted(false);
                    int insertResult = userLikeRepository.insert(newLike);
                    log.info("创建新记录结果: {}, 新记录ID={}", insertResult, newLike.getId());
                }
            } else {
                // 创建新记录
                log.info("创建新的点赞记录");
                UserLike newLike = new UserLike();
                newLike.setUserId(userId);
                newLike.setTargetType("tutorial");
                newLike.setTargetId(tutorialId);
                newLike.setDeleted(false);
                int insertResult = userLikeRepository.insert(newLike);
                log.info("创建新记录结果: {}, 新记录ID={}", insertResult, newLike.getId());
            }
            
            // 更新点赞数
            Integer currentLikeCount = tutorial.getLikeCount() == null ? 0 : tutorial.getLikeCount();
            tutorial.setLikeCount(currentLikeCount + 1);
            newLikedStatus = true;
            log.info("点赞成功，新的点赞数={}", tutorial.getLikeCount());
        }

        // 更新教程统计
        log.info("更新教程统计信息: tutorialId={}, likeCount={}", tutorialId, tutorial.getLikeCount());
        int tutorialUpdateResult = tutorialRepository.updateById(tutorial);
        log.info("教程更新结果: {}", tutorialUpdateResult);

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("isLiked", newLikedStatus);
        result.put("liked", newLikedStatus);
        result.put("likeCount", tutorial.getLikeCount());
        result.put("message", newLikedStatus ? "点赞成功" : "取消点赞成功");

        log.info("点赞操作完成: isLiked={}, likeCount={}", newLikedStatus, tutorial.getLikeCount());
        return result;
    }
    
    /**
     * 处理重复键异常，使用幂等逻辑提供友好的用户体验
     */
    private Map<String, Object> handleDuplicateKeyException(Long userId, Long tutorialId) {
        log.info("处理重复键异常: userId={}, tutorialId={}", userId, tutorialId);
        
        try {
            // 重新查询教程
            Tutorial tutorial = tutorialRepository.selectById(tutorialId);
            if (tutorial == null) {
                throw new BusinessException("教程不存在");
            }
            
            log.info("重复键异常转为幂等处理: userId={}, tutorialId={}", userId, tutorialId);
            // 直接调用幂等处理逻辑
            return handleLikeIdempotent(userId, tutorialId, tutorial);
            
        } catch (Exception e) {
            log.error("处理重复键异常时发生错误: {}", e.getMessage());
            
            // 最后的兜底策略：查询当前状态并返回友好消息
            try {
                Tutorial tutorial = tutorialRepository.selectById(tutorialId);
                if (tutorial != null) {
                    // 查询当前状态（包括所有记录）
                    List<UserLike> allLikes = userLikeRepository.findAllRecords(userId, "tutorial", tutorialId);
                    UserLike activeLike = allLikes.stream()
                            .filter(like -> !like.getDeleted())
                            .findFirst()
                            .orElse(null);
                    
                    boolean isLiked = activeLike != null;
                    
                    Map<String, Object> result = new HashMap<>();
                    result.put("isLiked", isLiked);
                    result.put("liked", isLiked);
                    result.put("likeCount", tutorial.getLikeCount());
                    result.put("message", isLiked ? "您已经点赞过了" : "检测到重复操作，请刷新页面查看最新状态");
                    
                    log.info("兜底策略处理完成: isLiked={}", isLiked);
                    return result;
                }
            } catch (Exception ex) {
                log.error("兜底策略也失败了: {}", ex.getMessage());
            }
            
            throw new BusinessException("点赞状态异常，请刷新页面重试");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> favoriteTutorial(Long tutorialId, Long userId) {
        log.info("用户{}收藏教程: {}", userId, tutorialId);

        // 参数校验
        if (tutorialId == null || tutorialId <= 0) {
            log.warn("收藏失败: 教程ID无效 - {}", tutorialId);
            throw new BusinessException("教程ID无效");
        }
        
        if (userId == null || userId <= 0) {
            log.warn("收藏失败: 用户ID无效 - {}", userId);
            throw new BusinessException("用户未登录或登录已过期，请重新登录");
        }

        // 使用用户+教程维度的同步锁，防止同一用户对同一教程的并发操作
        String lockKey = "favorite_tutorial_" + userId + "_" + tutorialId;
        synchronized (lockKey.intern()) {
            try {
                // 检查教程是否存在
                Tutorial tutorial = tutorialRepository.selectById(tutorialId);
                if (tutorial == null) {
                    log.warn("收藏失败: 教程不存在 - tutorialId={}", tutorialId);
                    throw new BusinessException("教程不存在");
                }
                
                // 检查教程状态
                if (tutorial.getDeleted() || tutorial.getStatus() != 1) {
                    log.warn("收藏失败: 教程状态无效 - tutorialId={}, deleted={}, status={}", 
                            tutorialId, tutorial.getDeleted(), tutorial.getStatus());
                    throw new BusinessException("该教程暂时无法收藏");
                }

                // 使用幂等操作处理收藏
                Map<String, Object> result = handleFavoriteIdempotent(userId, tutorialId, tutorial);
                return result;

            } catch (BusinessException e) {
                // 业务异常直接抛出
                throw e;
            } catch (Exception e) {
                log.error("收藏教程系统异常: tutorialId={}, userId={}", tutorialId, userId, e);
                throw new BusinessException("收藏操作失败，请稍后重试");
            }
        }
    }
    
    /**
     * 幂等处理收藏操作
     */
    private Map<String, Object> handleFavoriteIdempotent(Long userId, Long tutorialId, Tutorial tutorial) {
        log.info("执行幂等收藏处理: userId={}, tutorialId={}", userId, tutorialId);
        
        // 查询现有记录（包括已删除的）- 使用自定义SQL绕过@TableLogic
        List<UserFavorite> allFavorites = userFavoriteRepository.findAllRecords(userId, "tutorial", tutorialId);
        log.info("查询到{}条相关收藏记录（包括已删除）", allFavorites.size());
        
        // 打印详细的记录信息用于调试
        for (UserFavorite favorite : allFavorites) {
            log.info("收藏记录详情: ID={}, deleted={}, createTime={}", 
                    favorite.getId(), favorite.getDeleted(), favorite.getCreateTime());
        }
        
        // 查找有效记录
        UserFavorite activeFavorite = allFavorites.stream()
                .filter(fav -> !fav.getDeleted())
                .findFirst()
                .orElse(null);

        boolean newFavoritedStatus;
        
        if (activeFavorite != null) {
            // 已收藏，执行取消收藏 - 使用专门的软删除方法绕过逻辑删除限制
            log.info("发现有效收藏记录，执行取消收藏: 记录ID={}", activeFavorite.getId());
            int updateResult = userFavoriteRepository.softDeleteRecord(activeFavorite.getId());
            log.info("取消收藏更新结果: {}", updateResult);
            
            // 更新收藏数
            Integer currentFavoriteCount = tutorial.getFavoriteCount() == null ? 0 : tutorial.getFavoriteCount();
            tutorial.setFavoriteCount(Math.max(0, currentFavoriteCount - 1));
            newFavoritedStatus = false;
            log.info("取消收藏成功: 记录ID={}, 新的收藏数={}", activeFavorite.getId(), tutorial.getFavoriteCount());
        } else {
            // 未收藏，执行收藏操作
            log.info("未发现有效收藏记录，执行收藏操作");
            UserFavorite deletedFavorite = allFavorites.stream()
                    .filter(UserFavorite::getDeleted)
                    .findFirst()
                    .orElse(null);
            
            if (deletedFavorite != null) {
                // 重用已删除记录 - 使用专门的恢复方法绕过逻辑删除限制
                log.info("重用已删除收藏记录: 记录ID={}", deletedFavorite.getId());
                int updateResult = userFavoriteRepository.restoreDeletedRecord(deletedFavorite.getId());
                log.info("重用收藏记录更新结果: {}", updateResult);
                
                if (updateResult == 0) {
                    log.warn("重用收藏记录失败，创建新记录替代: 原记录ID={}", deletedFavorite.getId());
                    // 如果重用失败，创建新记录
                    UserFavorite newFavorite = new UserFavorite();
                    newFavorite.setUserId(userId);
                    newFavorite.setTargetType("tutorial");
                    newFavorite.setTargetId(tutorialId);
                    newFavorite.setDeleted(false);
                    int insertResult = userFavoriteRepository.insert(newFavorite);
                    log.info("创建新收藏记录结果: {}, 新记录ID={}", insertResult, newFavorite.getId());
                }
            } else {
                // 创建新记录
                log.info("创建新的收藏记录");
                UserFavorite newFavorite = new UserFavorite();
                newFavorite.setUserId(userId);
                newFavorite.setTargetType("tutorial");
                newFavorite.setTargetId(tutorialId);
                newFavorite.setDeleted(false);
                int insertResult = userFavoriteRepository.insert(newFavorite);
                log.info("创建新收藏记录结果: {}, 新记录ID={}", insertResult, newFavorite.getId());
            }
            
            // 更新收藏数
            Integer currentFavoriteCount = tutorial.getFavoriteCount() == null ? 0 : tutorial.getFavoriteCount();
            tutorial.setFavoriteCount(currentFavoriteCount + 1);
            newFavoritedStatus = true;
            log.info("收藏成功，新的收藏数={}", tutorial.getFavoriteCount());
        }

        // 更新教程统计
        log.info("更新教程收藏统计信息: tutorialId={}, favoriteCount={}", tutorialId, tutorial.getFavoriteCount());
        int tutorialUpdateResult = tutorialRepository.updateById(tutorial);
        log.info("教程收藏统计更新结果: {}", tutorialUpdateResult);

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("isFavorited", newFavoritedStatus);
        result.put("favorited", newFavoritedStatus);
        result.put("favoriteCount", tutorial.getFavoriteCount());
        result.put("message", newFavoritedStatus ? "收藏成功" : "取消收藏成功");

        log.info("收藏操作完成: isFavorited={}, favoriteCount={}", newFavoritedStatus, tutorial.getFavoriteCount());
        return result;
    }

    @Override
    public Map<String, Object> getTutorialInteraction(Long tutorialId, Long userId) {
        log.info("获取用户{}对教程{}的互动状态", userId, tutorialId);

        // 参数校验
        if (tutorialId == null || tutorialId <= 0) {
            log.warn("获取互动状态失败: 教程ID无效 - {}", tutorialId);
            throw new BusinessException("教程ID无效");
        }
        
        if (userId == null || userId <= 0) {
            log.warn("获取互动状态失败: 用户ID无效 - {}", userId);
            throw new BusinessException("用户未登录或登录已过期，请重新登录");
        }

        try {
            Map<String, Object> interaction = new HashMap<>();

            // 检查点赞状态
            LambdaQueryWrapper<UserLike> likeWrapper = new LambdaQueryWrapper<>();
            likeWrapper.eq(UserLike::getUserId, userId)
                       .eq(UserLike::getTargetType, "tutorial")
                       .eq(UserLike::getTargetId, tutorialId)
                       .eq(UserLike::getDeleted, false);

            boolean isLiked = userLikeRepository.selectCount(likeWrapper) > 0;

            // 检查收藏状态
            LambdaQueryWrapper<UserFavorite> favoriteWrapper = new LambdaQueryWrapper<>();
            favoriteWrapper.eq(UserFavorite::getUserId, userId)
                          .eq(UserFavorite::getTargetType, "tutorial")
                          .eq(UserFavorite::getTargetId, tutorialId)
                          .eq(UserFavorite::getDeleted, false);

            boolean isFavorited = userFavoriteRepository.selectCount(favoriteWrapper) > 0;

            // 返回结果，提供两种字段名以兼容前端
            interaction.put("isLiked", isLiked);
            interaction.put("liked", isLiked);
            interaction.put("isFavorited", isFavorited);
            interaction.put("favorited", isFavorited);

            return interaction;

        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            log.error("获取教程互动状态系统异常: tutorialId={}, userId={}", tutorialId, userId, e);
            // 对于查询操作，返回默认值而不是抛异常，避免前端报错
            Map<String, Object> defaultInteraction = new HashMap<>();
            defaultInteraction.put("isLiked", false);
            defaultInteraction.put("liked", false);
            defaultInteraction.put("isFavorited", false);
            defaultInteraction.put("favorited", false);
            return defaultInteraction;
        }
    }
}